from selenium import webdriver
import time
from selenium.webdriver import ActionChains, Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

FLAG = True  # 是否停止抢票，True代表抢，False代表停止抢

# 防止反爬
def anit_crawler():
    # 反爬处理
    # 浏览器配置对象
    options = webdriver.EdgeOptions()
    # 关闭受控提示
    options.add_experimental_option("excludeSwitches", ["enable-automation"])
    options.add_experimental_option("useAutomationExtension", False)
    # 禁用浏览器通知、麦克风和摄像头权限的提示框, 保存密码提示框
    options.add_experimental_option("prefs", {
        "profile.default_content_setting_values.notifications": 2,
        "profile.default_content_setting_values.media_stream_mic": 2,
        "profile.default_content_setting_values.media_stream_camera": 2,
        'credentials_enable_service': False,
        'profile.password_manager_enabled': False,
    })
    # # 切换仿真设备
    # mobile_emulation = {
    #     "deviceName": "iPhone 12 Pro"
    # }
    # options.add_experimental_option("mobileEmulation", mobile_emulation)
    # 反爬虫特征处理
    options.add_argument('--disable-blink-features=AutomationControlled')
    # # 打开开发者工具
    # options.add_argument("--auto-open-devtools-for-tabs")
    print("反爬处理结束")
    return options


# 登录功能
def login_fun(driver, login_url):
    # 浏览器发送请求
    driver.get(login_url)

    # 进入iframe
    driver.switch_to.frame(0)

    # 定位元素切换到账号密码输入
    driver.find_element(By.XPATH, '//a[@class="password-login-link"]').click()
    """
    find_element()
    功能：driver对象的方法，查找网页中的元素
    参数：1、指定查找方式 2、语法
    返回值：WebElement元素对象
    """
    # 定位账号密码的input元素，输入账号密码
    driver.find_element(By.ID, 'fm-login-id').send_keys('你自己的账号')
    driver.find_element(By.ID, 'fm-login-password').send_keys('你自己的密码')
    # 定义行为链
    try:
        time.sleep(0.5)
        driver.switch_to.frame(0)

        slider = driver.find_element(By.XPATH, '//span[@id="nc_1_n1z"]')

        # 1、初始化一个行为链对象
        actions = ActionChains(driver)
        # 2、定义行为
        actions.click_and_hold(slider)  # 点击并拖拽元素
        actions.move_by_offset(1170, 0)  # 向右拖拽1115像素
        actions.release()  # 松开鼠标

        # 3、执行行为链
        actions.perform()  # 执行所有ActionChains中的事件

        time.sleep(0.5)
        # 点击登录
        driver.find_element(By.XPATH, '//button[@type="submit"]').click()
    except:
        # 点击登录
        driver.find_element(By.XPATH, '//button[@type="submit"]').click()
    finally:
        time.sleep(2)  # 防止登录过快
        print("登录账号结束")


# 买票下单
def buy_tickets(driver, target_url):
    global FLAG
    driver.get(target_url)
    # 等待输入yes开抢票
    input('请输入yes开启抢票\n>>>')
    while FLAG:
        try:
            # 请求买票页面
            driver.get(target_url)
            try:
                # time.sleep(1)
                # 点击知道了
                know = WebDriverWait(driver, 3).until(
                    EC.presence_of_element_located((By.XPATH, '//div[@class="content"]/div[@class="button"]'))
                )
                # 有些温馨提示需要下滑才能点击确认
                # element = driver.find_element(By.XPATH, '//div[@class="content"]')
                # scroll_height = driver.execute_script("return arguments[0].scrollHeight;", element)
                # driver.execute_script("window.scrollTo(0, %s);" % scroll_height)
                know.click()
            except:
                pass

            # 进行购买
            WebDriverWait(driver, 3).until(
                EC.presence_of_element_located((By.XPATH, '//div[@class="buy__button"]'))
            ).click()

            # 等待选择时间的界面出现
            WebDriverWait(driver, 3).until(
                EC.presence_of_element_located((By.XPATH, '//div[@class="sku-content"][1]/div'))
            )
            # 选择时间
            element_list1 = driver.find_elements(By.XPATH, '//div[@class="sku-content"][1]/div')
            for element in element_list1:
                try:
                    element.click()
                    print("选择时间成功")
                    break
                except:
                    print("选择时间失败")

            # 等待票价的出现
            WebDriverWait(driver, 1).until(
                EC.presence_of_element_located((By.XPATH, '//div[contains(@class, "sku-tickets-card")]/div[2]/div'))
            )

            # 选择票价
            element_list2 = driver.find_elements(By.XPATH, '//div[contains(@class, "sku-tickets-card")]/div[2]/div')
            for _ in range(5):  # 循环抢5抡，如果还抢不到就刷新页面再抢
                if not FLAG:    # 当抢成功后就退出for循环
                    break
                for element in element_list2:
                    try:
                        element.click()
                        # 等待点击购买的按键亮起
                        WebDriverWait(driver, 3).until(
                            # EC.presence_of_element_located((By.XPATH, '//div[@class="sku-footer-bottom"]/div[position()=last()]'))
                            EC.presence_of_element_located((By.XPATH, '//div[@class="sku-footer-bottom"]/div[2]'))
                        ).click()
                        print('选票成功')
                        # 选票成功后停止抢票
                        FLAG = False
                        time.sleep(3)
                        break
                    except:
                        print('选票失败')
        except Exception as e:
            print(e)


# 确认订单
def confirm_order(driver):
    while True:
        try:

            # 等待观影人选择按钮出现并点击选择观影人
            WebDriverWait(driver, 3).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, '.iconfont.icondanxuan-weixuan_'))
            ).click()
            print("观影人选择成功")
        except:
            print("观影人选择失败")

        try:
            time.sleep(3)
            # 点击提交订单
            WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.XPATH, '//div[@view-name="TextView"]'))
            )
            order = driver.find_elements(By.XPATH, '//div[@view-name="TextView"]')[-1]
            order.click()
            print("提交订单成功")
            break
        except:
            print("提交订单失败")


def main():
    # 定义URL
    base_url = "https://m.damai.cn/damai/home/index.html"
    # 五月天（6月2日10点55分）
    # target_url = "https://m.damai.cn/damai/detail/item.html?itemId=721216860314&spm=a2o71.search.list.ditem_0&sqm=dianying.h5.unknown.value"  # 五月天

    # 张艺兴（6月3日13点14分）
    # target_url = "https://m.damai.cn/damai/detail/item.html?itemId=721571231867&spm=a2o71.home.snatch_ticket.item&sqm=dianying.h5.unknown.value"

    # 测试
    target_url = "https://m.damai.cn/damai/detail/item.html?itemId=720545258599&spm=a2o71.search.list.ditem_0&sqm=dianying.h5.unknown.value"

    login_url = "https://m.damai.cn/damai/minilogin/index.html"

    # 进行反爬处理
    options = anit_crawler()
    # 实例化driver
    driver = webdriver.Edge(options=options)
    # 将webdriver属性置空，实现反爬
    driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {
        'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'
    })

    # # 测试
    # driver.get(login_url)

    # 登录账号
    login_fun(driver, login_url)
    # 选择票
    buy_tickets(driver, target_url)
    # 订单确认
    confirm_order(driver)

    input('>>>')
    # 退出浏览器
    driver.quit()


if __name__ == '__main__':
    main()
